راهنمای جامع در مورد Bypass کردن AMSI
مایکروسافت استاندارد Antimalware Scan Interface (AMSI) را توسعه داد که به توسعهدهندگان امکان میدهد مکانیزمهای دفاع در برابر بدافزار را در نرمافزار خود ادغام کنند. AMSI این قابلیت را فراهم میکند که یک برنامه با هر آنتیویروس نصبشده روی سیستم تعامل داشته باشد و از اجرای بدافزارهای پویا و مبتنی بر اسکریپت جلوگیری کند. در این مقاله، به بررسی دقیقتر AMSI، نحوهی پیادهسازی آن در کد و همچنین برخی از روشهای شناختهشده Bypass خواهیم پرداخت.
فهرست مطالب
- پیشزمینه
- نامگذاری بدافزارها
- نحوه عملکرد AMSI
- روشهای Bypass کردن AMSI
- روش اول: Powershell Downgrade
- روش دوم: مبهمسازی کد
- روش سوم:ایجاد خطای اجباری
- روش چهارم: Memory Hijacking
- روش پنجم: ربایش حافظه با استفاده از Opcodeهای مبهمسازیشده
- روش ششم دورزدن AMSI با Reflection
- روش هفتم: اسکریپت یکپارچه Nishang
- نتیجهگیری
پیشزمینه
به طور خلاصه، مایکروسافت یک API اسکن بدافزارهای مبتنی بر اسکریپت ارائه کرده است که توسعهدهندگان میتوانند آن را در هر نرمافزاری ادغام کنند تا ورودیهای کاربر را اسکن و اعتبارسنجی کرده و از این طریق، امنیت برنامه و کاربران آن را در برابر بدافزارها تضمین نمایند. به عنوان نمونه، یک اپلیکیشن پیامرسان میتواند قبل از ارسال پیام به گیرنده، محتوای آن را با AMSI اسکن کرده و در صورت وجود بدافزار، آن را مسدود کند.
AMSI مستقل از فروشنده بوده و به توسعهدهندگان از طریق رابطهای Win32 API و COM قابلیت استفاده میدهد. از آنجایی که مایکروسافت مدیریت مستقیم AMSI را بر عهده دارد، آخرین Signatureهای بدافزار به صورت خودکار در آن بهروزرسانی میشوند. بنابراین، یک توسعهدهنده میتواند با سهولت، AMSI را در برنامه خود پیادهسازی کند تا از کاربران در برابر بدافزارهای پویا و مبتنی بر اسکریپت محافظت نماید.
عملکرد AMSI مبتنی بر Signature-based Detection است. به این معنا که برای هر کلیدواژه مخرب، URL، تابع یک Signature مرتبط در پایگاه دادهی آن ثبت شده است. در نتیجه، اگر مهاجم مجدداً همان کلیدواژه یا الگو را در کد خود به کار گیرد، AMSI بلافاصله اجرای آن را مسدود خواهد کرد.
نامگذاری بدافزارها
پیش از بررسی جزئیات عملکرد AMSI، لازم است بدانیم که بدافزارها چگونه نامگذاری میشوند. در بسیاری از موارد، هنگام تحلیل، ویندوز تنها وجود بدافزار را تشخیص میدهد اما تحلیلگران قادر به شناسایی دقیق جزئیات و رفتار بدافزار نیستند. به همین دلیل، سازمان Computer Antivirus Research Organisation (CARO) یک استاندارد نامگذاری برای بدافزارها تعریف کرده است.
برای نمونه، یک Backdoor مبتنی بر Shortcut که با خانوادهی Caphaw مرتبط است، به شکل زیر نامگذاری میشود:
نحوه عملکرد AMSI
به عنوان یک توسعهدهنده، میتوانید از AMSI برای پیادهسازی مکانیزمهای دفاعی در برابر بدافزار استفاده کنید. فرض کنید یک نرمافزار طراحی کردهاید که ورودی کاربر را به صورت یک اسکریپت دریافت کرده و آن را از طریق یک Scripting Engine مانند PowerShell اجرا میکند. در همان لحظهای که ورودی دریافت میشود، میتوان AMSI را فراخوانی کرد تا ابتدا محتوای ورودی از نظر وجود بدافزار بررسی شود.
ویندوز برای فراخوانی AMSI، رابطهای COM و Win32 API را در اختیار توسعهدهندگان قرار میدهد.
جریان کاری AMSI به شکل زیر است:
- برنامه ورودی (مانند اسکریپت) را از کاربر دریافت میکند.
- قبل از اجرا، ورودی به AMSI ارسال میشود.
- AMSI محتوای ورودی را با استفاده از Signatureهای ذخیرهشده بررسی میکند.
- در صورت شناسایی الگوهای مخرب، اجرای اسکریپت متوقف میشود.
- در غیر این صورت، اسکریپت برای اجرا به Scripting Engine تحویل داده میشود.
توضیحات
همانطور که مشاهده میکنید، AMSI API یک رابط Open است، بنابراین هر آنتیویروس میتواند دادهها را از طریق توابع آن دریافت کند. در این مثال، یک Windows Script در حال اجرا است. زمانی که این اسکریپت از طریق AMSI پردازش میشود، فایل amsi.dll در همان فضای حافظهی مجازی برنامه تزریق میگردد.
فایل amsi.dll شامل مجموعهای از توابع است که قابلیت ارزیابی کد را دارند. لیست این توابع موجود است، اما وظیفه اصلی اسکن توسط دو تابع زیر انجام میشود:
- AmsiScanString()
- AmsiScanBuffer()
این توابع مسئول تحلیل و بررسی کد هستند. در صورتی که کد پاک باشد، AV Provider Class نتایج را دریافت کرده و از طریق یک RPC Call به خدمت آنتیویروسارسال میکند. اما اگر کد مشکوک تشخیص داده شود، خود AMSI اجرای آن را مسدود خواهد کرد.
روشهای Bypass کردن AMSI
اکنون که مفاهیم پایهی AMSI را بررسی کردیم، به برخی از تکنیکهای شناختهشده برای Bypass کردن AMSI میپردازیم. انجام AMSI Bypass برای Red Teamers در بسیاری از سناریوها ضروری است، بهویژه زمانی که نیاز به اجرای کد دلخواه جهت Lateral Movement یا Privilege Escalation وجود دارد.
پوشش تمامی روشهای موجود در حوزهی AMSI Bypass فراتر از محدودهی این مقاله است، چرا که هر روز روشهای جدیدی معرفی میشوند. در این مستند، تنها به روشهای برجسته و شناختهشده پرداخته و آنها را روی Windows 10 نسخه ۱۸۰۹ آزمایش میکنیم. شایان ذکر است که در نسخههای جدیدتر ویندوز (بالاتر از ۱۹۰۳)، مایکروسافت با بهروزرسانی مستمر Signatureها، تقریباً تمامی روشهای رایج موجود در اینترنت را مسدود کرده است.
نکته:
AMSI برخی کلیدواژهها مانند “invoke-mimikatz” یا “amsiutils” را مسدود میکند، زیرا این دستورات در میان کارشناسان امنیت بهطور گسترده به عنوان ابزار Exploitation شناخته میشوند. بنابراین در این مقاله، صرفاً به عنوان Proof of Concept (PoC) این دستورات را پس از اجرای Bypass بررسی میکنیم، اما هیچ Payload واقعی در اینجا Bypass نخواهد شد.
مایکروسافت AMSI را در PowerShell Terminal (برنامه powershell.exe) ادغام کرده است. این برنامه ورودی کاربر را دریافت کرده و آن را از طریق PowerShell Engine پردازش میکند. در صورتی که با ابزار Process Hacker جستجو کنید، مشاهده خواهید کرد که فایل amsi.dll در حال اجرا در PowerShell Terminal است و قبل از هرگونه اجرای کد، ورودیها ابتدا توسط آن اسکن میشوند.
روش اول Powershell Downgrade
در صورتی که یک PowerShell-based payload اجرا کنید و AMSI مانع اجرای آن شود، میتوانید نسخه PowerShell را به ۲٫۰ Downgrade کنید؛ زیرا AMSI تنها نسخههای بالاتر از v2.0 را پشتیبانی میکند. در ابتدا میتوان مشاهده کرد که AMSI کلمات کلیدی ما را مسدود میکند.
بیایید نسخه فعلی PowerShell (PS) را بررسی کنیم، سپس آن را به نسخه ۲ Downgrade کرده و این دستورات مسدودشده را مجدداً اجرا نماییم.
$PSVersionTable "amsiutils" powershell -version 2 "amsiutils"
اما همانطور که قابلتصور است، بزرگترین Drawback در اینجا آن است که بسیاری از قابلیتها یا اسکریپتهای مدرن روی PowerShell 2.0 اجرا نخواهند شد. بنابراین، بیایید به بررسی روشهای دیگر بپردازیم.
روش دوم Obfuscation
Obfuscation به تکنیکی اشاره دارد که طی آن کد به شکلی پیچیده و غیرقابلخواندن تبدیل میشود. AMSI بر اساس برخی Keywords مشخص، Signatures را شناسایی میکند؛ بنابراین Obfuscating این Keywords مؤثر خواهد بود. به عنوان مثال، بیایید دستور invoke-mimikatz را Obfuscate کنیم.
Invoke-Mimikatz "Inv”+"o+"ke"+"-Mimi"+"katz"
همانطور که مشاهده میکنید، تنها با شکستن یک String و الحاق آنها با استفاده از عملگر + توانستیم AMSI را دور بزنیم.
با این حال، این تکنیک معایب خاص خود را دارد. یک Payload ممکن است یک یا چند بار باعث فعالشدن AMSI شود. عملاً بسیار زمانبر و پر از نویز است که پس از هر بار اجرای یک Payload، مجبور به Obfuscate کردن Keywordها به صورت موردی باشیم. به همین دلیل ما این راهنمای Manual Obfuscation ارائهشده توسط @ShitSecure را دنبال میکنیم.
ابزار AmsiTrigger توسط RhytmStick توسعه یافته است که میتواند یک Script/Payload را در برابر AMSI اسکن کرده و دقیقاً مشخص کند کدام خطوط موجب فعالشدن AMSI خواهند شد؛ سپس میتوانیم همان بخشها را Obfuscate کنیم. شما میتوانید این ابزار را از اینجا دانلود کنید.
اکنون ما اسکریپتی به نام demo.ps1 با دستورات زیر ایجاد کردهایم:
میخواهیم این اسکریپت را با استفاده از AmsiTrigger در برابر AMSI بررسی کنیم. این کار را میتوان به شکل زیر انجام داد:
.\demo.ps1 .\AmsiTrigger.ps1 -i .\demo.ps1
اکنون ابزار خطوطی را که AMSI در آنها اجرای کد را مسدود میکند مشخص کرده است. میتوانیم با استفاده از روش String Concatenation آنها را Obfuscate کنیم، به این صورت:
"am"+"si"+"ut"+"ils" "in"+"vok"+"e"+"-"+"mi"+"mik"+"atz"
اکنون این دستورات قابل اجرا بوده و میتوانند با موفقیت AMSI را دور بزنند.
همچنین میتوانید از وبسایت https://amsi.fail برای Obfuscate کردن کد خود استفاده کنید.
روش سوم Forcing an error
Matt Graeber در توییت خود به روشی برای دور زدن AMSI اشاره کرده است. تابع amsiInitFailed() در صورتی مقدار ۰ بازمیگرداند که سناریوهای ذکرشده در بالا باعث آغاز یک اسکن توسط AMSI شوند. این روش دور زدن در اصل مقدار Boolean True را به amsiInitFailed تخصیص میدهد تا فرآیند AMSI Initialization با خطا مواجه شود؛ در نتیجه هیچ اسکن دیگری برای Process جاری انجام نخواهد گرفت. کد آن به شکل زیر است:
$mem = [System.Runtime.InteropServices.Marshal]::AllocHGlobal(9076) [Ref].Assembly.GetType("System.Management.Automation.AmsiUtils").GetField("amsiSession","NonPublic,Static").SetValue($null, $null);[Ref].Assembly.GetType("System.Management.Automation.AmsiUtils").GetField("amsiContext","NonPublic,Static").SetValue($null, [IntPtr]$mem)
از آن زمان تاکنون، افراد زیادی نسخههای مختلفی از همان روش را منتشر کردهاند. در برخی روشها از Bytecode استفاده میشود، در برخی دیگر توابع یا رشتهها جایگزین میشوند، اما منطق اصلی روش یکسان باقی میماند.
روش چهارم Memory Hijacking
Daniel Duggan در وبلاگ خود درباره تکنیکهای Memory Hijacking که میتوانند AMSI را دور بزنند، مطلبی منتشر کرده است. منطق این روش Hooking تابع AmsiScanBuffer() است (برای مطالعه درباره Hooking اینجا را ببینید) بهگونهای که این تابع همواره مقدار AMSI_RESULT_CLEAN را بازگرداند، که نشان میدهد AMSI هیچ بدافزاری پیدا نکرده است. پاسخهای API نیز میتوانند با استفاده از ابزار API Monitor ساختهی Rohitab مانیتور شوند.
ابتدا بیایید اسکریپت Invoke-Mimikatz را دانلود کرده و بررسی کنیم که AMSI بهدرستی در حال کار است.
اکنون کد اصلی در اینجا ارائه شده است. با این حال، برای کاهش پیچیدگی در فرایند Compile کردن کد بهصورت DLL، میتوانید Fork من را از اینجا بررسی کنید. پس از دانلود، اطمینان حاصل کنید که نام Main Package را از “AmsiScanBufferBypass” به “Project” یا هر نام دلخواه دیگری تغییر دهید؛ زیرا AMSI رشته “AmsiScanBufferBypass” را نیز مسدود میکند!
پس از دانلود، به پوشه Release بروید و مشاهده خواهید کرد که یک فایل DLL با نام ASBBypass.dll وجود دارد.
توجه داشته باشید که از آنجا که اکنون یک DLL در اختیار داریم، میتوانیم آن را با EXE Payload خود نیز ادغام کنیم و در لحظه، AMSI را دور بزنیم!
با این حال، در اینجا ما از کد C# بهصورت In-line استفاده میکنیم تا Patch را تنها از طریق PowerShell Terminal فعال کنیم. این کار به شکل زیر قابل انجام است:
[System.Reflection.Assembly]::LoadFile("C:\users\hex\Project\ASBBypass.dll") [Amsi]::Bypass()
همانطور که مشاهده میکنید، AMSI اکنون با موفقیت دور زده شده است.
روش پنجم Memory Hijacking (Obfuscated Opcodes)
پس از شناسایی تکنیک Rasta Mouse (Daniel Duggan)، افراد تغییرات مختلفی در کد ایجاد کردند تا مجدداً FUD شود. Fatrodzianko در وبلاگ خود درباره یکی از این تکنیکها مطلبی منتشر کرده است. او همان کد را با استفاده از Opcodes، Obfuscate کرده و اسکریپت را در Gist قرار داده است.
برای اجرای اسکریپت، کافی است آن را دانلود کرده، تغییر نام دهید (برای جلوگیری از شناسایی Keyword توسط AMSI) و سپس به شکل زیر اجرا کنید:
"invoke-mimikatz" .\my-am-bypass.ps1 "invoke-mimikatz"
همانطور که مشاهده میکنید، ما اکنون با موفقیت توانستهایم AMSI را دور بزنیم.
روش ششم AMSI Bypass با استفاده از Reflection
بر اساس مستندات Microsoft: «Reflection اشیائی (Objects) از نوع Type ارائه میدهد که Assemblies، Modules و Types را توصیف میکنند. میتوانید از Reflection برای ایجاد پویا (Dynamically) یک نمونه از یک Type، اتصال Type به یک شیء موجود، یا بهدستآوردن Type از یک شیء موجود و فراخوانی متدها یا دسترسی به فیلدها و Properties آن استفاده کنید. اگر در کد خود از Attributes استفاده کنید، Reflection امکان دسترسی به آنها را نیز فراهم میکند.» (اطلاعات بیشتر را میتوانید اینجا مطالعه کنید).
Paul Laine روش اصلی Memory Hijacking را در وبلاگ contextis.com منتشر کرد. Shantanu Khandelwal همان کد را با استفاده از تکنیک Reflection معرفیشده توسط Matt Graeber، بهصورت یک In-Memory Patch کامل بازنویسی کرد. این تغییر باعث شد کد مخفیانهتر عمل کند؛ چرا که دیگر هیچ Artefact روی دیسک باقی نمیماند. (مشاهده بیشتر در وبسایت او).
ما نسخه اصلی Patch را نمایش نخواهیم داد، بلکه بهروزرسانی مبتنی بر Reflection از اینجا دانلود میشود. مطمئن شوید که پس از دانلود، اسکریپت را تغییر نام دهید و از Keywordsی مانند “amsibypass” و … استفاده نکنید، زیرا توسط AMSI مسدود میشوند. من نام فایل را به “am-bp-reflection.ps1” تغییر دادهام.
"invoke-mimikatz" .\am-bp-reflection.ps1 "invoke-mimikatz"
روش هفتم اسکریپت Nishang All in One
Nikhil Mittal یک اسکریپت AMSI Bypass را به ابزار شناختهشده خود با نام Nishang اضافه کرده است که میتوانید آن را از اینجا دریافت کنید. این اسکریپت شش روش مختلف برای دور زدن AMSI را در یک اجرا ترکیب میکند. این روشها عبارتند از:
- unload – روشی از Matt Graeber. ماژول AMSI را از نشست جاری PowerShell خارج میکند.
- unload2 – روش دیگری از Matt Graeber. AMSI را از نشست جاری PowerShell خارج میکند.
- unloadsilent – روش دیگری از Matt Graeber. AMSI را خارج کرده و از WMF5 Autologging جلوگیری میکند.
- unloadobfuscated – نسخه Obfuscated شدهی روش unload با استفاده از ابزار Invoke-Obfuscation توسعهیافته توسط Daniel Bohannon – که از WMF5 Autologging جلوگیری میکند.
- dllhijack – روشی از Cornelis de Plaa. در این روش، فایل amsi.dll مورد استفاده در کد از پروژه p0wnedshell (لینک: https://github.com/Cn33liz/p0wnedShell) گرفته میشود.
- psv2 – اگر نسخهی .NET 2.0.50727 روی ویندوز ۱۰ موجود باشد، PowerShell v2 اجرا خواهد شد که از AMSI پشتیبانی نمیکند.
تنها کافی است اسکریپت را دانلود کرده و اجرا کنید؛ ابزار بهطور خودکار با استفاده از یک روش معتبر، AMSI را دور میزند. برای مثال، در اینجا WMF5 Autologging Bypass عمل کرده است. این روش AMSI را از Terminal جاری خارج کرده و آن را دور میزند.
اسکریپت را از اینجا دانلود کرده، نام آن را به “nishang.ps1” تغییر دهید و به شکل زیر اجرا کنید:
Import-Module .\nishang.ps1 Invoke-AmsiBypass -Verbose “invoke-mimikatz”
نتیجهگیری
در این مقاله درباره مبانی AMSI، نحوه استفاده از آن در یک برنامه، Workflow و هفت روش برای دور زدن آن صحبت کردیم. توجه داشته باشید که روشهای بیشتری برای این کار وجود دارد، اما هدف این مقاله بررسی هفت روش شناختهشدهتر برای AMSI Bypass، روند تکامل این رویکردها در طول زمان و افزایش پیچیدگی آنها بود. امیدواریم این مقاله برای شما مفید بوده باشد. با تشکر از همراهی شما.